import sys
import random

from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QTableView
from PyQt5.QtCore import QVariant, QAbstractTableModel, Qt, pyqtSignal, QModelIndex
from PyQt5.QtGui import QColor


class MyTableView(QTableView):
    """View"""
    SelectedCellSignal = pyqtSignal(QModelIndex)

    def __init__(self):
        super(MyTableView, self).__init__()

    def mousePressEvent(self, e):
        """重写鼠标点击事件。"""
        if e.button() == Qt.RightButton:
            return super().mousePressEvent(e)

        index = self.indexAt(e.pos())
        return self.SelectedCellSignal.emit(index)


class MyTableModel(QAbstractTableModel):
    """Model"""
    def __init__(self):
        super(MyTableModel, self).__init__()
        self._data = []
        self._background_color = []
        self._headers = ['序号', '姓名', '性别', '年龄']

        self._generate_data()

    def _generate_data(self):
        """填充表格数据"""
        name_list = ['张三', '李四', '王五', '王小二', '李美丽', '王二狗']

        for id_num, name in enumerate(name_list):
            self._data.append([str(id_num), name, '男', str(random.randint(20, 25))])

            # :默认单元格颜色为白色
            self._background_color.append([QColor(255, 255, 255) for i in range(4)])

    def rowCount(self, parent=QModelIndex()):
        """返回行数量。"""
        return len(self._data)

    def columnCount(self, parent=QModelIndex()):
        """返回列数量。"""
        return len(self._headers)

    def headerData(self, section, orientation, role):
        """设置表格头"""
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self._headers[section]

    def data(self, index, role):
        """显示表格中的数据。"""
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return QVariant()

        row = index.row()
        col = index.column()

        if role == Qt.DisplayRole:
            return self._data[row][col]
        elif role == Qt.BackgroundColorRole:
            return self._background_color[row][col]
        elif role == Qt.TextAlignmentRole:
            return Qt.AlignCenter

        return QVariant()

    def cellPaint(self, index, color):
        """给单元格填充颜色。"""
        row = index.row()
        col = index.column()

        self._background_color[row][col] = QColor(color)
        self.layoutChanged.emit()


class ColorfulTable(QWidget):
    def __init__(self):
        super().__init__()

        self.tableView = MyTableView()
        self.tableModel = MyTableModel()
        self.tableView.setModel(self.tableModel)

        self.tableView.SelectedCellSignal.connect(self.selectedCell)

        layout = QHBoxLayout()
        layout.addWidget(self.tableView)
        self.setLayout(layout)

    def selectedCell(self, index):
        """鼠标点击事件槽函数。"""
        color = '#{}'.format(''.join([hex(random.randint(0, 256))[2:].rjust(2, '0') for i in range(3)]))
        self.tableModel.cellPaint(index, color)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    test = ColorfulTable()
    test.show()
    sys.exit(app.exec_())
